#include "soaQueryFilePathInfo.h"

#include <iostream>
#include <thread>
#include "public_define.h"
#include "adr_component.h"
#include "dc_util.h"
#include <dirent.h>
#include <sys/stat.h>
#include "common_opr_all.h"

#include "QueryFilePathInfo.pb.h"

using namespace DcAdr;

SoaQueryFilePathInfo::SoaQueryFilePathInfo()
{
}

SoaQueryFilePathInfo::~SoaQueryFilePathInfo()
{
}

SoaQueryFilePathInfo &SoaQueryFilePathInfo::getInstance()
{
    static SoaQueryFilePathInfo info;
    return info;
}

void SoaQueryFilePathInfo::setPublishHandle(adr_component *component)
{
    m_component = component;
}

void SoaQueryFilePathInfo::Get_QueryFilePathInfo(const std::string &topic, const std::string &requestData, std::string &replyData)
{
    Log_Info("[SoaQueryFilePathInfo] [Get_QueryFilePathInfo]");

    Soa::PB_QueryFilePathInfo_Get_QueryFilePathInfo_In queryFilePath;
    if (!queryFilePath.ParsePartialFromString(requestData))
    {
        Log_ERROR("SoaQueryFilePathInfo parse proto data failed , topic: {}", topic);
    }

    std::string controllerCode = queryFilePath.controllercode();
    std::string searchPath = queryFilePath.searchpath();

    string tempfilePathList = "";
    string tempmsg = "";

    Soa::PB_FilePathInfo ret;

    // FilePathInfo ret;

    //是TBOX才填值
    if (!controllerCode.compare(global_data::g_controler_code))
    {
        getPathFileInfo(searchPath, tempfilePathList, tempmsg);
    }
    else
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(5000));
        tempmsg = "error,controllerCode is " + controllerCode + "not " + global_data::g_controler_code;
        tempfilePathList = tempmsg;
    }

    Soa::PB_QueryFilePathInfo_Get_QueryFilePathInfo_Out queryFilePathOut;

    queryFilePathOut.mutable_return_()->set_code(2001);
    queryFilePathOut.mutable_return_()->set_filepathlist(tempfilePathList);
    queryFilePathOut.mutable_return_()->set_msg(tempmsg);

    queryFilePathOut.SerializePartialToString(&replyData);

    Log_Info("[QueryFilePathInfo] SoaQueryFilePathInfo succ!");

    return;
}

// 定义SoaQueryFilePathInfo类的getPathFileInfo方法，用于获取指定文件夹路径下的文件信息
// 参数：folderPath（目标文件夹路径）、filePathList（输出参数，存储文件信息的JSON字符串）、resmsg（输出参数，操作结果消息）
void SoaQueryFilePathInfo::getPathFileInfo(const std::string &folderPath, std::string &filePathList, std::string &resmsg)
{
    Json::Value fileArray;  // 用于存储多个文件信息的JSON数组
    string tmp;             // 临时变量，未使用
    
    // 检查输入的文件夹路径是否为空
    if (folderPath.empty())
    {
        resmsg = "error,filepath is empty";  // 设置错误消息：路径为空
        return;                              // 退出函数
    }

    // 打开目标文件夹，返回目录流指针
    DIR *dir = opendir(folderPath.c_str());
    // 检查文件夹是否成功打开
    if (NULL == dir)
    {
        resmsg = "error,dir is error";  // 设置错误消息：打开目录失败
        return;                         // 退出函数
    }

    struct dirent *dir_info;  // 用于存储目录项信息的结构体指针
    struct stat s_buf;        // 用于存储文件状态信息的结构体

    string absPath = "";  // 用于存储文件的绝对路径
    
    // 循环读取目录中的每个条目，直到没有更多条目（dir_info为nullptr）
    while ((dir_info = readdir(dir))!=nullptr)
    {
        // 拼接文件的绝对路径（文件夹路径 + 文件名）
        absPath = folderPath + dir_info->d_name;

        // 跳过当前目录（.）和上级目录（..）
        if (0 == strncmp(dir_info->d_name, ".", 1) || 0 == strncmp(dir_info->d_name, "..", 2))
        {
            continue;
        }

        // 获取文件状态信息（如大小、修改时间、文件类型等）
        // 若获取失败，跳过当前文件
        if (0 != stat(absPath.c_str(), &s_buf))
        {
            continue;
        }

        Json::Value fileJson;  // 用于存储单个文件信息的JSON对象
        
        // 填充文件信息到JSON对象
        fileJson["controllerCode"] = global_data::g_controler_code;  // 控制器编码（全局变量）
        fileJson["fileName"] = dir_info->d_name;                     // 文件名
        fileJson["filePath"] = absPath;                              // 文件绝对路径

        // 判断文件类型（文件或目录）
        string filetype = "file";  // 默认设为文件
        if (S_ISDIR(s_buf.st_mode))  // 若为目录
        {
            filetype = "directory";  // 修改为目录类型
        }
        fileJson["fileType"] = filetype;                  // 文件类型
        fileJson["modifyDate"] = to_string(s_buf.st_mtime);  // 最后修改时间（时间戳）
        fileJson["fileSize"] = to_string(s_buf.st_size);     // 文件大小（字节）
        
        fileArray.append(fileJson);  // 将单个文件的JSON对象添加到数组中
    }
    
    closedir(dir);  // 关闭目录流
    dir_info = NULL;  // 指针置空，避免野指针

    Json::FastWriter writer;  // 用于将JSON对象转换为字符串的快速写入器
    filePathList = writer.write(fileArray);  // 将文件信息数组转换为JSON字符串
    
    // 去除JSON字符串中的换行符（格式化处理）
    CommonOprJson::jsonstrformat(filePathList);
    
    resmsg = "success,get fileinfo success";  // 设置成功消息

    // 记录日志：成功获取文件信息，并输出文件列表
    Log_Info("[SoaQueryFilePathInfo] getPathFileInfo succ! filePathList: {}", filePathList);
    return;  // 退出函数
}